home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / glchess / display.py < prev    next >
Encoding:
Python Source  |  2009-09-22  |  17.7 KB  |  561 lines

  1. # -*- coding: utf-8 -*-
  2. __author__ = 'Robert Ancell <bob27@users.sourceforge.net>'
  3. __license__ = 'GNU General Public License Version 2'
  4. __copyright__ = 'Copyright 2005-2006  Robert Ancell'
  5.  
  6. import config
  7. import player
  8. import scene
  9. import scene.cairo
  10. import scene.opengl
  11. import scene.human
  12. import ui
  13. import game
  14. import chess.board
  15.  
  16. class MovePlayer(game.ChessPlayer):
  17.     """This class provides a pseudo-player to watch for piece movements"""
  18.  
  19.     def __init__(self, view):
  20.         """Constructor for a move player.
  21.         
  22.         'view' is the view to update
  23.         """
  24.         self.view = view
  25.         game.ChessPlayer.__init__(self, '@view')
  26.  
  27.     # Extended methods
  28.  
  29.     def onPieceMoved(self, piece, start, end, delete):
  30.         """Called by chess.board.ChessPlayer"""
  31.         if self.view.moveNumber != -1:
  32.             return
  33.         animate = self.view.game.isStarted()
  34.         p = self.view.scene.movePiece(piece, end, delete, animate)
  35.  
  36.         # If a player move notify when animation completes
  37.         if animate and self.view.moveNumber == -1 and start is not None and start != end:
  38.             self.view.scene.waitingPiece = p
  39.  
  40.     def onPlayerMoved(self, p, move):
  41.         self.view._redrawHighlight()
  42.         
  43.     def onPlayerStartTurn(self, player):
  44.         self.view._redrawHighlight()
  45.  
  46. class CairoPiece(scene.ChessPieceFeedback):
  47.     """
  48.     """
  49.  
  50.     def __init__(self, scene, piece):
  51.         self.scene = scene
  52.         self.piece = piece
  53.         self.model = None
  54.         self.location = ''
  55.  
  56.     def onDeleted(self):
  57.         """Called by scene.ChessPieceFeedback"""
  58.         self.scene.pieces.pop(self.piece)
  59.  
  60.     def onMoved(self):
  61.         """Called by scene.ChessPieceFeedback"""
  62.         self.scene.view._pieceMoved(self)
  63.  
  64. class SceneCairo(scene.SceneFeedback, scene.human.SceneHumanInput):
  65.     """
  66.     """
  67.  
  68.     def __init__(self, view):
  69.         """
  70.         """
  71.         self.view = view
  72.         self.controller = scene.cairo.Scene(self)
  73.         self.game = view.game
  74.         self.pieces = {}
  75.         self.waitingPiece = None
  76.         scene.human.SceneHumanInput.__init__(self)
  77.         
  78.     def getPieces(self):
  79.         return self.pieces.values()
  80.  
  81.     def movePiece(self, piece, location, delete, animate):
  82.         """
  83.         """
  84.         # Get the model for this piece creating one if it doesn't exist
  85.         try:
  86.             p = self.pieces[piece]
  87.         except KeyError:
  88.             # Make the new model
  89.             pieceName = {chess.board.PAWN: 'pawn', chess.board.ROOK: 'rook', chess.board.KNIGHT: 'knight',
  90.                          chess.board.BISHOP: 'bishop', chess.board.QUEEN: 'queen', chess.board.KING: 'king'}[piece.getType()]
  91.             chessSet = {chess.board.WHITE: 'white', chess.board.BLACK: 'black'}[piece.getColour()]
  92.             p = CairoPiece(self, piece)
  93.             p.model = self.controller.addChessPiece(chessSet, pieceName, location, p)
  94.             self.pieces[piece] = p
  95.  
  96.         # Move the model
  97.         p.location = location
  98.         p.model.move(location, delete, animate)
  99.         
  100.         return p
  101.  
  102.     # Extended methods
  103.  
  104.     def onRedraw(self):
  105.         """Called by scene.cairo.Scene"""
  106.         if self.game.view is not None and self.game.view.controller is not None:
  107.             self.game.view.controller.render()
  108.  
  109.     def startAnimation(self):
  110.         """Called by scene.cairo.Scene"""
  111.         self.game.application.ui.controller.startAnimation()
  112.         
  113.     def getSquare(self, x, y):
  114.         """Called by scene.human.SceneHumanInput"""
  115.         return self.controller.getSquare(x, y)
  116.  
  117.     def playerIsHuman(self):
  118.         """Called by scene.human.SceneHumanInput"""
  119.         return self.game.currentPlayerIsHuman()
  120.  
  121.     def squareIsFriendly(self, coord):
  122.         """Called by scene.human.SceneHumanInput"""
  123.         return self.playerIsHuman() and self.game.squareIsFriendly(coord)
  124.     
  125.     def canMove(self, start, end):
  126.         """Called by scene.human.SceneHumanInput"""
  127.         return self.playerIsHuman() and self.game.getCurrentPlayer().canMove(start, end) # FIXME: Promotion type
  128.  
  129.     def selectSquare(self, coord):
  130.         """Called by scene.human.SceneHumanInput"""
  131.         self.view.setSelectedSquare(coord)
  132.  
  133.     def moveHuman(self, start, end):
  134.         """Called by scene.human.SceneHumanInput"""
  135.         self.game.moveHuman(start, end)
  136.         
  137. class OpenGLPiece(scene.ChessPieceFeedback):
  138.     """
  139.     """
  140.  
  141.     def __init__(self, scene, piece):
  142.         self.scene = scene
  143.         self.piece = piece
  144.         self.model = None
  145.         self.location = ''
  146.  
  147.     def onDeleted(self):
  148.         """Called by scene.ChessPieceFeedback"""
  149.         self.scene.pieces.pop(self.piece)
  150.  
  151.     def onMoved(self):
  152.         """Called by scene.ChessPieceFeedback"""
  153.         self.scene.view._pieceMoved(self)
  154.  
  155. class SceneOpenGL(scene.SceneFeedback, scene.human.SceneHumanInput):
  156.     """
  157.     """   
  158.  
  159.     def __init__(self, view):
  160.         """Constructor for a glChess scene.
  161.         
  162.  
  163.         """
  164.         self.view = view
  165.         self.game = view.game
  166.         self.pieces = {}
  167.         self.waitingPiece = None
  168.  
  169.         # Call parent constructors
  170.         self.controller = scene.opengl.Scene(self)
  171.         scene.human.SceneHumanInput.__init__(self)
  172.  
  173.     def getPieces(self):
  174.         return self.pieces.values()
  175.         
  176.     def movePiece(self, piece, location, delete, animate):
  177.         """
  178.         """
  179.         # Get the model for this piece creating one if it doesn't exist
  180.         try:
  181.             p = self.pieces[piece]
  182.         except KeyError:
  183.             # Make the new model
  184.             pieceName = {chess.board.PAWN: 'pawn', chess.board.ROOK: 'rook', chess.board.KNIGHT: 'knight',
  185.                          chess.board.BISHOP: 'bishop', chess.board.QUEEN: 'queen', chess.board.KING: 'king'}[piece.getType()]
  186.             chessSet = {chess.board.WHITE: 'white', chess.board.BLACK: 'black'}[piece.getColour()]
  187.             p = OpenGLPiece(self, piece)
  188.             p.model = self.controller.addChessPiece(chessSet, pieceName, location, p)
  189.             self.pieces[piece] = p
  190.             
  191.         # Move the model
  192.         p.location = location
  193.         p.model.move(location, delete)
  194.  
  195.         return p
  196.  
  197.     # Extended methods
  198.  
  199.     def onRedraw(self):
  200.         """Called by scene.opengl.Scene"""
  201.         if self.game.view is not None and self.game.view.controller is not None:
  202.             self.game.view.controller.render()
  203.  
  204.     def startAnimation(self):
  205.         """Called by scene.opengl.Scene"""
  206.         self.game.application.ui.controller.startAnimation()
  207.         
  208.     def getSquare(self, x, y):
  209.         """Called by scene.human.SceneHumanInput"""
  210.         return self.controller.getSquare(x, y)
  211.  
  212.     def playerIsHuman(self):
  213.         """Called by scene.human.SceneHumanInput"""
  214.         return self.game.currentPlayerIsHuman()
  215.  
  216.     def squareIsFriendly(self, coord):
  217.         """Called by scene.human.SceneHumanInput"""
  218.         return self.playerIsHuman() and self.game.squareIsFriendly(coord)
  219.     
  220.     def canMove(self, start, end):
  221.         """Called by scene.human.SceneHumanInput"""
  222.         return self.playerIsHuman() and self.game.getCurrentPlayer().canMove(start, end) # FIXME: Promotion type
  223.     
  224.     def selectSquare(self, coord):
  225.         """Called by scene.human.SceneHumanInput"""
  226.         self.view.setSelectedSquare(coord)
  227.     
  228.     def moveHuman(self, start, end):
  229.         """Called by scene.human.SceneHumanInput"""
  230.         self.game.moveHuman(start, end)
  231.  
  232. class Splashscreen(ui.ViewFeedback):
  233.     """
  234.     """
  235.  
  236.     def __init__(self, application):
  237.         """Constructor.
  238.         
  239.         'application' is ???
  240.         """
  241.         self.application = application
  242.         self.cairoScene = scene.cairo.Scene(self)
  243.         self.scene = scene.opengl.Scene(self)
  244.  
  245.     def updateRotation(self, animate = True):
  246.         boardView = config.get('board_view')
  247.         if boardView == 'black':
  248.             rotation = 180.0
  249.         else:
  250.             rotation = 0.0
  251.         self.cairoScene.controller.setBoardRotation(rotation, boardView == 'facetoface', animate)
  252.         self.scene.controller.setBoardRotation(rotation, boardView == 'facetoface', animate)
  253.  
  254.     def onRedraw(self):
  255.         """Called by scene.SceneFeedback"""
  256.         if self.controller is not None:
  257.             self.controller.render()
  258.             
  259.     def showBoardNumbering(self, showNumbering):
  260.         """Called by ui.ViewFeedback"""
  261.         self.scene.showBoardNumbering(showNumbering)
  262.         self.cairoScene.showBoardNumbering(showNumbering)
  263.  
  264.     def showMoveHints(self, showHints):
  265.         """Called by ui.ViewFeedback"""
  266.         pass
  267.  
  268.     def renderGL(self):
  269.         """Called by ui.ViewFeedback"""
  270.         self.scene.render()
  271.         
  272.     def renderCairoStatic(self, context):
  273.         """Called by ui.ViewFeedback"""
  274.         return self.cairoScene.renderStatic(context)
  275.         
  276.     def renderCairoDynamic(self, context):
  277.         """Called by ui.ViewFeedback"""
  278.         self.cairoScene.renderDynamic(context)
  279.     
  280.     def reshape(self, width, height):
  281.         """Called by ui.ViewFeedback"""
  282.         self.scene.reshape(width, height)
  283.         self.cairoScene.reshape(width, height)
  284.  
  285.     def select(self, x, y):
  286.         pass
  287.     
  288.     def deselect(self, x, y):
  289.         pass    
  290.  
  291.     def selectSquare(self, coord):
  292.         pass
  293.     
  294.     def undo(self):
  295.         """Called by ui.ViewFeedback"""
  296.         pass
  297.  
  298.     def resign(self):
  299.         """Called by ui.ViewFeedback"""
  300.         pass
  301.     
  302.     def claimDraw(self):
  303.         """Called by ui.ViewFeedback"""
  304.         pass
  305.     
  306.     def setMoveNumber(self, moveNumber):
  307.         """Called by ui.ViewFeedback"""
  308.         pass
  309.  
  310. class View(ui.ViewFeedback):
  311.     """
  312.     """
  313.  
  314.     def __init__(self, game):
  315.         """Constructor.
  316.         
  317.         'game' is the game this view is rendering
  318.         """
  319.         self.game = game
  320.         
  321.         # The move we are watching
  322.         self.moveNumber = -1
  323.         
  324.         # The selected square
  325.         self.selectedCoord = None
  326.         self.showHints = False
  327.         self.showNumbering = False
  328.         self.doSmooth = False
  329.         self.highlightParams = (None, None, None, None)
  330.         self.changedHighlight = True
  331.         
  332.         self.controller  = None
  333.         
  334.         # Use a Cairo scene by default - it will be replaced by an OpenGL one if that is the requested view
  335.         # I wanted to remove this but then scene is None and there are a number of issues...
  336.         # This should be cleaned up
  337.         self.scene = SceneCairo(self)
  338.         config.watch('board_view', self.__onBoardViewChanged)
  339.  
  340.         # Look for game events to update the scene
  341.         movePlayer = MovePlayer(self)
  342.         game.addSpectator(movePlayer)
  343.  
  344.     def setSelectedSquare(self, coord):
  345.         if self.selectedCoord == coord:
  346.             return
  347.         self.selectedCoord = coord
  348.         self._redrawHighlight()
  349.  
  350.     def _redrawHighlight(self):
  351.         self.changedHighlight = True
  352.         if self.controller is not None:
  353.             self.controller.render()
  354.  
  355.     def __onBoardViewChanged(self, key, value):
  356.         self.updateRotation()
  357.  
  358.     def _updateHighlight(self, coord):
  359.         if self.moveNumber == -1:
  360.             player = self.game.getCurrentPlayer()
  361.             if player is self.game.getWhite():
  362.                 colour = chess.board.WHITE
  363.             else:
  364.                 colour = chess.board.BLACK
  365.         else:
  366.             if self.moveNumber % 2 == 0:
  367.                 colour = chess.board.WHITE
  368.             else:
  369.                 colour = chess.board.BLACK
  370.  
  371.         # Don't update if nothing has changed
  372.         params = (colour, self.moveNumber, self.selectedCoord, self.showHints)
  373.         if self.highlightParams == params:
  374.             return
  375.         self.highlightParams = params
  376.  
  377.         highlights = {}
  378.         if self.showHints:
  379.             for file in '12345678':
  380.                 for rank in 'abcdefgh':
  381.                     c = rank + file
  382.                     highlight = None
  383.                     if self.game.board.squareUnderAttack(colour, c, moveNumber = self.moveNumber):
  384.                         highlight = scene.HIGHLIGHT_THREATENED
  385.                     elif coord is not None:
  386.                         move = self.game.board.testMove(colour, coord, c, moveNumber = self.moveNumber)
  387.                         if move is not None:
  388.                             if self.game.board.getPiece(c, self.moveNumber):
  389.                                 highlight = scene.HIGHLIGHT_CAN_TAKE
  390.                             else:
  391.                                 highlight = scene.HIGHLIGHT_CAN_MOVE
  392.  
  393.                     if highlight is not None:
  394.                         highlights[c] = highlight
  395.         if coord is not None:
  396.             highlights[coord] = scene.HIGHLIGHT_SELECTED
  397.  
  398.         self.scene.controller.setBoardHighlight(highlights)
  399.  
  400.     def updateRotation(self, animate = True):
  401.         """
  402.         """
  403.         # Get the angle to face
  404.         p = self.game.getCurrentPlayer()
  405.         if p is self.game.getWhite():
  406.             rotation = 0.0
  407.         elif p is self.game.getBlack():
  408.             rotation = 180.0
  409.         
  410.         # Decide if we should face this angle
  411.         boardView = config.get('board_view')
  412.         if boardView == 'white' or boardView == 'facetoface':
  413.             rotation = 0.0
  414.         elif boardView == 'black':
  415.             rotation = 180.0
  416.         elif boardView == 'human':
  417.             if not isinstance(p, player.HumanPlayer):
  418.                 return
  419.  
  420.         self.scene.controller.setBoardRotation(rotation, boardView == 'facetoface', animate)
  421.  
  422.     def _pieceMoved(self, piece):
  423.         """
  424.         """
  425.         self._redrawHighlight()
  426.         
  427.         # If waiting for this piece then end players turn
  428.         if piece is not None and piece is self.scene.waitingPiece:
  429.             self.scene.waitingPiece = None
  430.             self.game.getCurrentPlayer().endMove()
  431.  
  432.     def showMoveHints(self, showHints):
  433.         """Called by ui.ViewFeedback"""
  434.         self.showHints = showHints
  435.         self._redrawHighlight()
  436.  
  437.     def showBoardNumbering(self, showNumbering):
  438.         """Called by ui.ViewFeedback"""
  439.         self.showNumbering = showNumbering
  440.         self.scene.controller.showBoardNumbering(showNumbering)
  441.         
  442.     def showSmooth(self, doSmooth):
  443.         """Called by ui.ViewFeedback"""
  444.         self.doSmooth = doSmooth
  445.         self.scene.controller.showSmooth(doSmooth)
  446.  
  447.     def updateScene(self, sceneClass):
  448.         """
  449.         """
  450.         if self.changedHighlight:
  451.             self._updateHighlight(self.selectedCoord)
  452.         self.changedHighlight = False
  453.         
  454.         if isinstance(self.scene, sceneClass):
  455.             return
  456.         self._pieceMoved(None)
  457.         self.scene = sceneClass(self)
  458.         self.reshape(self.width, self.height)
  459.         self.setMoveNumber(self.moveNumber)
  460.         self.showBoardNumbering(self.showNumbering)
  461.         self.showSmooth(self.doSmooth)
  462.         self.updateRotation(animate = False)
  463.  
  464.     def renderGL(self):
  465.         """Called by ui.ViewFeedback"""
  466.         self.updateScene(SceneOpenGL)
  467.         self.scene.controller.render()
  468.  
  469.     def renderCairoStatic(self, context):
  470.         """Called by ui.ViewFeedback"""
  471.         self.updateScene(SceneCairo)
  472.         return self.scene.controller.renderStatic(context)
  473.         
  474.     def renderCairoDynamic(self, context):
  475.         """Called by ui.ViewFeedback"""
  476.         self.updateScene(SceneCairo)
  477.         self.scene.controller.renderDynamic(context)
  478.  
  479.     def reshape(self, width, height):
  480.         """Called by ui.ViewFeedback"""
  481.         self.width = width
  482.         self.height = height
  483.         self.scene.controller.reshape(width, height)
  484.     
  485.     def select(self, x, y):
  486.         """Called by ui.ViewFeedback"""
  487.         self.scene.select(x, y)
  488.     
  489.     def deselect(self, x, y):
  490.         """Called by ui.ViewFeedback"""
  491.         self.scene.deselect(x, y)
  492.     
  493.     def setMoveNumber(self, moveNumber):
  494.         """Called by ui.ViewFeedback"""
  495.         self.moveNumber = moveNumber
  496.         
  497.         # Lock the scene if not tracking the game
  498.         self.scene.enableHumanInput(moveNumber == -1)
  499.         
  500.         # Get the state of this scene
  501.         piecesByLocation = self.game.getAlivePieces(moveNumber)
  502.         
  503.         # Remove any models not present
  504.         requiredPieces = piecesByLocation.values()
  505.         for piece in self.scene.getPieces():
  506.             try:
  507.                 requiredPieces.index(piece.piece)
  508.             except ValueError:
  509.                 piece.model.move(piece.location, True)
  510.         
  511.         # Move the models in the scene
  512.         for (location, piece) in piecesByLocation.iteritems():
  513.             self.scene.movePiece(piece, location, False, True)
  514.  
  515.         # Can't wait for animation if not looking at the latest move
  516.         if moveNumber != -1:
  517.             self._pieceMoved(piece)
  518.  
  519.         self._redrawHighlight()
  520.  
  521.     def save(self, fileName = None):
  522.         """Called by ui.ViewFeedback"""
  523.         # If filename supplied take out of the history
  524.         if fileName is not None:
  525.             if self.game.inHistory:
  526.                 self.game.inHistory = False
  527.                 if self.game.fileName is not None:
  528.                     self.game.application.history.rename(self.game.fileName, fileName)
  529.             self.game.fileName = fileName
  530.         return self.game.save()
  531.  
  532.     def getFileName(self):
  533.         """Called by ui.ViewFeedback"""
  534.         # If in the history then prompt for a new name
  535.         if self.game.inHistory:
  536.             return None
  537.         return self.game.fileName
  538.     
  539.     def undo(self):
  540.         """Called by ui.ViewFeedback"""
  541.         p = self.game.getHumanPlayer()
  542.         if p is not None:
  543.             p.undo()
  544.         
  545.     def resign(self):
  546.         """Called by ui.ViewFeedback"""
  547.         p = self.game.getHumanPlayer()
  548.         if p is None:
  549.             # If no human players then abandon game
  550.             self.game.abandon()
  551.         else:
  552.             p.resign()
  553.             
  554.     def claimDraw(self):
  555.         """Called by ui.ViewFeedback"""
  556.         # TODO: Have the UI ask if the player wants to make a move first or claim now (or abort)
  557.         p = self.game.getHumanPlayer()
  558.         if p is None:
  559.             return False
  560.         return p.claimDraw()
  561.